//
// Created by wlk12 on 2023/3/17.
//
#include <iostream>

enum class A : uint32_t
{
    a1 = 1 << 0,
    a2 = 1 << 1,
    a3 = 1 << 2,
};

enum class B
{
    b1 = 1 << 0,
    b2 = 1 << 1,
    b3 = 1 << 2,
};

class C
{
public:
    explicit operator uint32_t () { return 1; }
};


template<typename T>
using enable_bit_option_t = std::enable_if_t<(std::is_integral_v<T> || std::is_same_v<T, A>)>;

template<typename T1, typename T2, typename = enable_bit_option_t<T1> , typename = enable_bit_option_t<T2>>
uint32_t operator | (T1 left, T2 right)
{
    return static_cast<uint32_t>(left) | static_cast<uint32_t>(right);
}

template<typename T, typename  = enable_bit_option_t<T>>
uint32_t& operator |= (uint32_t& left, T right)
{
    left = left | static_cast<uint32_t>(right);
    return left;
}

template<typename T1, typename T2, typename = enable_bit_option_t<T1> , typename = enable_bit_option_t<T2>>
uint32_t operator & (T1 left, T2 right)
{
    return static_cast<uint32_t>(left) & static_cast<uint32_t>(right);
}


struct SA
{
    using FlagType = uint32_t;

    static constexpr FlagType sa1 = 1 << 0;
    static constexpr FlagType sa2 = 1 << 2;
    static constexpr FlagType sa3 = 1 << 3;

    SA(FlagType v = 0) : value(v) {}

    operator FlagType& ()
    {
        return value;
    }

private:
    FlagType value;
};

int main()
{
    auto as = A::a1 | A::a2 | 0;
    as |= A::a3;

//    as |= B::b1;
//    as = 1 | C();

    std::cout << "as = " << as << std::endl;
    std::cout << "as & A::a2 = " << (as & A::a2) << "\n\n" << std::endl;

    auto as2 = 2 | 4;
    std::cout << "as2 = " << as2 << std::endl;

    SA a;
    a = 2;
    a | SA::sa1;

    return  0;
}

